/*
*
* Copyright (c) 2011 Vaulting Systems International
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy 
* of this software and associated documentation files (the "Software"), to deal 
* in the Software without restriction, including without limitation the rights 
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 
* of the Software, and to permit persons to whom the Software is furnished to do  
* so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all  
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, 
* INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 
* PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 
* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE  
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package com.ekeyman.client.rest.test;

import java.security.Security;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.testng.annotations.AfterSuite;
import org.testng.annotations.BeforeSuite;
import org.testng.annotations.Test;

import com.ekeyman.client.rest.service.EkeymanService;
import com.ekeymanlib.dto.AppDeviceApiKeys;
import com.ekeymanlib.dto.EncryptionKeys;

public class MyOnlineBillpayAppUT {
	
	private static final String[] SPRING_CONFIG_FILES = new String[]{"applicationContext.xml"};
	
	@Test
	public void testMyOnlineBillpayApp() {

		System.out.println("Entered testMyOnlineBillpayApp...");
		
	    try {
	    	/*
	    	 * The EkeymanService implementation is a Spring bean.
	    	 * Bouncy Castle is the crypto service provider.
	    	 */
	    	ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext(SPRING_CONFIG_FILES);
	    	EkeymanService ekeymanService = (EkeymanService)ctx.getBeanFactory().getBean("serviceClient");
			
	    	Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); 
		    Cipher cipher = Cipher.getInstance("AES/ECB/NoPadding", "BC"); 
		    
		    
			/*
			 * Register device for this application. This is typically done when an 
			 * application is first installed on a device. The application will need 
			 * to store the public and private keys locally, either in a database or 
			 * config file. The application also needs to provide a way to manually 
			 * enter a new private key in case a new one was generated due to a lost 
			 * or stolen device. After registering the device, the application no longer
			 * needs the vendor api key. For security reasons, it should be deleted 
			 * from the device once device registration is complete.
			 * 
			 */
			String apiKey = "46a971d9-e286-4907-b824-5da748aaa0a8";
			String application = "MyBillPayRestApp";
			String device = "708-555-1212";
			
			AppDeviceApiKeys appDeviceApiKeys = ekeymanService.registerAppDevice(
					apiKey, application, device);

			String publicKey = appDeviceApiKeys.getPublicKey();
			String privateKey = appDeviceApiKeys.getPrivateKey();
			
			
	    	/* 
	    	 * Create a set of encryption keys. The secretKeyLength value is used to
	    	 * generate a random key for secret key encryption. The ivLength, saltLength, 
	    	 * and iterationCountMax values are used to generate random keys for password
	    	 * based encryption. Note that each invocation of the ekeyman service optionally
	    	 * takes a location parameter to records the device location at the time of 
	    	 * the service call.
	    	 */
			String location = "35.22694,-80.84333";		// GPS coordinates 
			String resourceUri = "/Apps/OBP/TRN100-ID";	// Unique id for encrypted resource
			String transactionId = "983457863123459 ";	// String to be encrypted
			int secretKeyLength = 16; 		// number of bytes 
			int ivLength = 8; 				// number of bytes 
			int saltLength = 8; 			// number of bytes 
			int iterationCountMax = 1024; 	// integer max

	    	EncryptionKeys keysToEncrypt = ekeymanService.createEncryptionKeys(
	    			resourceUri, publicKey, privateKey, secretKeyLength, ivLength, 
	    			saltLength, iterationCountMax, location);


		    
		    /*
		     * Encryption pass using secret key encryption. After encryption, the application
		     * will need to store the cipherText locally. 
		     * 
		     */
	    	byte[] input = transactionId.getBytes();
	    	
		    SecretKeySpec encryptionKey = new SecretKeySpec(keysToEncrypt.getKeyBytes(), "AES");
		    byte[] cipherText = new byte[input.length];
		    cipher.init(Cipher.ENCRYPT_MODE, encryptionKey);
		    int ctLength = cipher.update(input, 0, input.length, cipherText, 0);
		    ctLength += cipher.doFinal(cipherText, ctLength);

		    
		    /*
		     * Decryption pass. The encryption keys are retrieved from ekeyman prior to
		     * data decryption. The application also needs to retrieve the cipherText 
		     * before decrypting. For this example, the bytes array containing the cipherText 
		     * is simply reused. After decryption, decryptedText should equal the original
		     * value for transactionId.
		     * 
		     */
			EncryptionKeys keysToDecrypt = ekeymanService.getEncryptionKeys(resourceUri, 
					publicKey, privateKey, location);
			
		    SecretKeySpec decryptionKey = new SecretKeySpec(keysToDecrypt.getKeyBytes(), "AES");
		    byte[] plainText = new byte[ctLength];
		    cipher.init(Cipher.DECRYPT_MODE, decryptionKey);
		    int ptLength = cipher.update(cipherText, 0, ctLength, plainText, 0);
		    ptLength += cipher.doFinal(plainText, ptLength);
		    String decryptedText = new String(plainText);

		    
		    // At this point the original text and decrypted text should match!!!!
		    assert transactionId.equals(decryptedText) : "Expected transactionId and decrypted text to match" + 
		    		" originalTransactionId: " + transactionId + " decryptedText: " + decryptedText;
		    
	    }
	    catch (Exception e){
	    	System.out.println(e.getMessage());
	    }
	    System.out.println("Exited testMyOnlineBillpayApp...");
	}

	
	@BeforeSuite
	public void beforeSuite() {
		System.out.println("Before suite...");
	}
	
	@AfterSuite
	public void afterSuite() {
		System.out.println("After suite...");
	}
}
